﻿using BodaNetCommunications.Cores;
using BodaNetCommunications.S7Coms.S7Utils;
using BodaNetCommunications.Utilities.Attributes;
using BodaNetCommunications.Utilities.ComTypes;
using BodaNetCommunications.Utilities.Results;

namespace BodaNetCommunications.S7Coms
{
    [ProtocolTypeAttribute(ProtocolType.S7)]
    public class S7CommService : CommReadWrite, IS7CommService
    {
        public ConnectionOptions Options { get; private set; }

        public S7Plc S7Plc { get; private set; }

        public bool IsConnected => S7Plc != null && S7Plc.IsConnected;

        public S7CommService()
        {
            base._byteTransform = new S7ByteTransformBase();
        }

        public void Dispose()
        {
            this.Disconnect();
        }

        public BodaResult Connect(ConnectionOptions connectionOptions)
        {
            Options = connectionOptions;

            if (IsConnected)
            {
                BodaResult bodaResult = new BodaResult();
                bodaResult.IsSuccess = true;
                bodaResult.Message = $"S7【{Options.Ip}:{Options.Port}】的连接已经在线，不需要重复连接";
                return bodaResult;
            }

            SiemensPlcType siemensPlc = (SiemensPlcType)Enum.Parse(typeof(SiemensPlcType), connectionOptions.PlcName);
            switch (siemensPlc)
            {
                case SiemensPlcType.S7200:
                    base._byteTransform.EndianType = Utilities.ComTypes.EndianType.ABCD;
                    break;
                case SiemensPlcType.Logo0BA8:
                    break;
                case SiemensPlcType.S7200Smart:
                    base._byteTransform.EndianType = Utilities.ComTypes.EndianType.ABCD;
                    Options.Rack = 0;
                    Options.Slot = 1;
                    break;
                case SiemensPlcType.S7300:
                    Options.Rack = 0;
                    Options.Slot = 2;
                    break;
                case SiemensPlcType.S7400:
                    break;
                case SiemensPlcType.S71200:
                    Options.Rack = 0;
                    Options.Slot = 0;
                    base._byteTransform.EndianType = Options.IsOptimized ? Utilities.ComTypes.EndianType.DCBA : Utilities.ComTypes.EndianType.ABCD;
                    break;
                case SiemensPlcType.S71500:
                    Options.Rack = 0;
                    Options.Slot = 0;
                    base._byteTransform.EndianType = Options.IsOptimized ? Utilities.ComTypes.EndianType.DCBA : Utilities.ComTypes.EndianType.ABCD;
                    break;
                default:
                    break;
            }

            S7Plc = new S7Plc();

            base.WordLength = 1;

            return S7Plc.Connect(Options);
        }

        public void Disconnect()
        {
            S7Plc?.Disconnect();
        }

        /// <summary>
        /// 重写基础数据的读取功能
        /// </summary>
        /// <param name="address">数据地址</param>
        /// <param name="length">数据个数</param>
        /// <returns></returns>
        public override BodaResult<byte[]> Read(string address, ushort length)
        {
            // 要将地址类型全部转换成字节类型，将DBD,DBR等等的转成DBB
            address = address.Trim().Replace("DBD", "DBB").Replace("DBW", "DBB").Replace("DBR", "DBB");

            //#if DEBUG
            //            Stopwatch sw = Stopwatch.StartNew();
            //#endif
            var res = S7Plc.Read<byte>(address, length);
            //#if DEBUG
            //            Console.WriteLine($"Read Time1: {sw.ElapsedMilliseconds}ms");
            //            sw.Stop();
            //#endif
            BodaResult<byte[]>? readResult = new BodaResult<byte[]>();
            if (res.IsSuccess)
            {
                readResult.Content = res.Datas.ToArray();
            }
            else
            {
                readResult.IsSuccess = false;
                readResult.Message = res.Message;
            }
            return readResult;
        }

        public override BodaResult Write(string address, byte[] value)
        {
            var res = S7Plc.Write(address, value);
            return res;
        }

        public BodaResult SendMsgc(byte[] bytes, int timeout = 1500)
        {
            throw new NotImplementedException();
        }

        public BodaResult<byte> ReceiveMsg(int timeout = 2000, int bytesLen = 1024)
        {
            throw new NotImplementedException();
        }
    }
}
